#include "stdafx.h"
#include ".\graph.h"
#include <iostream>
#include <fstream>
#include <time.h>
#include <math.h>
#include "graph.h"
#include <Windows.h>
using namespace std;

graph::graph(void) {
	int i, j, k;
	int basex,basey;
	int region;
	float tmpFloat;
	nodes_number = MAX_NODE_NUMBER;
	srand((unsigned int)time(NULL));

	//nodes[nodes_number];
	for(i=0;i<MAX_NODE_NUMBER;i++) {
		nodes[i].ID = i;
		nodes[i].userType = rand() % 5;
 		nodes[i].recipientList = NULL;
		nodes[i].nearby = NULL;
		nodes[i].on = 1;
		nodes[i].message = new messageInfo;
		nodes[i].neighbor_number = 0;
		nodes[i].sendDelayFactor = rand() % 100 / (float)100;
		nodes[i].recvDelayFactor = rand() % 100 / (float)100;
		nodes[i].hasSentTheSameMessage = false;
		for(j = 0; j < MAX_CHANNEL_NUMBER; j++){		// dice 5 random number
			nodes[i].channelPreference[j] = rand() % 100 / (float)100;
		}
		for(j = 0; j < MAX_CHANNEL_NUMBER; j++){
			for(k = j; k < MAX_CHANNEL_NUMBER; k++){
				if(nodes[i].channelPreference[j] > nodes[i].channelPreference[k]){
					tmpFloat = nodes[i].channelPreference[k];
					nodes[i].channelPreference[k] = nodes[i].channelPreference[j];
					nodes[i].channelPreference[j] = tmpFloat;
				}
			}
		}
	}


	// set up channel information
	for(i = 0; i < MAX_CHANNEL_NUMBER; i++){
		channels[i].channelID = i;
		channels[i].channelReceiveBaseDelay = rand() % 20;
		channels[i].channelReceiveBaseDelay = rand() % 20;
	}
}

graph::~graph(void) {
	free(nodes);
}

node graph::getNode(int nodeID)
{
	return nodes[nodeID];
}

void graph::setNode(node thisNode)
{
	nodes[thisNode.ID - 1] = thisNode;
}

// logic:
// before sending out a message, the recipient checks against its
// knowledge base to see whether this message has been received.
// if so, he or she won't feel like to forward it again to
// his or her neighbors
//int graph::send(int senderID, messageInfo *msg){
//	int recvTime;	// recvTime = time_now + send_delay + transmission_delay
//	// add indiviual send delay, transmission delay, append receive event
//	
//	//recvTime = msg->messageTimestamp + 
//	//	getSendDelay(msg->channelNumber, getNode(senderID)) + 
//	//	getTransmissionDelay(msg->channelNumber, getNode(msg->senderID), getNode(msg->recipientID));
//
//	//events::insertEventAtTimeT(
//	return 0;
//}

// Assumption: we assume people will forward a message only
// when he or she sees it at the first time, which means
// when receving the same message second time or more,
// the recipent gets bored and feel reluctant to forward it
// to others

// logic:
// open the message and add the delay time for checking out messages
// change the property of the message and store it to the user property 
// (node->messageInfo)
//int graph::receive(int recipientNodeID, messageInfo *message){
//	node recipient = getNode(recipientNodeID);
//	//
//	//message.sender = sender;
//	
//	if(recipient.hasSentTheSameMessage){
//		return -1;	// it has received the same message before. abort.
//	}else{
//		//message->messageTimestamp += (double) calcRecvDelay(channel, &recipient);
//		message->senderID = message->recipientID;
//
//		// schedule an send event
//		element *anEvent = new element;
//		anEvent->clock = message->messageTimestamp;
//
//		// queue anEvent to queue
//
//		
//	}
//	
//	return 0;
//}

bool graph::wantsToSendMessage(node senderNode, float prob){
	switch(senderNode.userType){
	case TEENAGER:
		if(WANTS_TO_FORWARD_MSG_TEENAGER > prob)		return true;
		break;
	case COMPUTERGEEK:
		if(WANTS_TO_FORWARD_MSG_COMPUTERGEEK > prob)	return true;
		break;
	case GRANDPARENTS:
		if(WANTS_TO_FORWARD_MSG_GRANDPARENTS > prob)	return true;
		break;
	case HOUSEWIFE:
		if(WANTS_TO_FORWARD_MSG_HOUSEWIFE > prob)		return true;
		break;
	case BUSINESSMAN:
		if(WANTS_TO_FORWARD_MSG_BUSINESSMAN > prob)		return true;
		break;
	}
	return false;
}

int graph::getChannelUsed(node senderNode, float prob){
	for(int i = MAX_CHANNEL_NUMBER - 2; i > -1; i--){		// in this case it starts with the 4th channel
		if(prob > senderNode.channelPreference[i]){
			return i+1;		// it means it uses the i+1 channel
		}
	}
	return 0;
}

// logic: send delay depends on what channel it's taking and individual user's habit
int graph::getSendDelay(int channelNum, node sender){
	switch(channelNum){
		case 0:		return SEND_DELAY_EMAIL * sender.sendDelayFactor + 1;
		case 1:		return SEND_DELAY_OSN * sender.sendDelayFactor + 1;
		case 2:		return SEND_DELAY_SMS * sender.sendDelayFactor + 1;
		case 3:		return SEND_DELAY_PHONE * sender.sendDelayFactor + 1;
		case 4:		return SEND_DELAY_HUMANCONTACT * sender.sendDelayFactor + 1;
	}
	// should not get here!
	return -1;
}

// logic: recv delay depends on what channel it's taking and individual user's habit
int graph::getTransmissionDelay(int channelNum, node sender, node recipient){
	switch(channelNum){
	case 0:		return TRANSMISSION_DELAY_EMAIL * 
					sqrt(pow((double)(sender.locationx - recipient.locationx), 2) + pow((double)(sender.locationy - recipient.locationy), 2)) / TRANSMISSION_DELAY_DISTANCE_DISCOUNT_FACTOR + 1;
	case 1:		return TRANSMISSION_DELAY_OSN * 
					sqrt(pow((double)(sender.locationx - recipient.locationx), 2) + pow((double)(sender.locationy - recipient.locationy), 2)) / TRANSMISSION_DELAY_DISTANCE_DISCOUNT_FACTOR + 1;
	case 2:		return TRANSMISSION_DELAY_SMS * 
					sqrt(pow((double)(sender.locationx - recipient.locationx), 2) + pow((double)(sender.locationy - recipient.locationy), 2)) / TRANSMISSION_DELAY_DISTANCE_DISCOUNT_FACTOR + 1;
	case 3:		return TRANSMISSION_DELAY_PHONE * 
					sqrt(pow((double)(sender.locationx - recipient.locationx), 2) + pow((double)(sender.locationy - recipient.locationy), 2)) / TRANSMISSION_DELAY_DISTANCE_DISCOUNT_FACTOR + 1;
	case 4:		return TRANSMISSION_DELAY_HUMANCONTACT * 
					sqrt(pow((double)(sender.locationx - recipient.locationx), 2) + pow((double)(sender.locationy - recipient.locationy), 2)) / TRANSMISSION_DELAY_DISTANCE_DISCOUNT_FACTOR + 1;
	}
	return -1;
}

// logic: recv delay depends on what channel it's taking and individual user's habit
int graph::getRecvDelay(int channelNum, node recipient){
	switch(channelNum){
		case 0:		return RECEIVE_DELAY_EMAIL * recipient.recvDelayFactor;
		case 1:		return RECEIVE_DELAY_OSN * recipient.recvDelayFactor;
		case 2:		return RECEIVE_DELAY_SMS * recipient.recvDelayFactor;
		case 3:		return RECEIVE_DELAY_PHONE * recipient.recvDelayFactor;
		case 4:		return RECEIVE_DELAY_HUMANCONTACT * recipient.recvDelayFactor;
	}
	return -1;
}

void graph::Readmap() {
	fstream map;
	int number = 0;
	int count = 0;
	int cl = 0;
	char c;
	int i = 0;
	neighbor *start = NULL;
	neighbor *index = NULL;

	map.open("map_300_average_5_neighbor_1&2_20.txt");
	if(!map) {
		cerr << "Can't open file!\n" << endl;
		system("pause");
		exit(1);
	}
	
	while(count < nodes_number) {
		cl = 0;

		//Set node ID
		map.get(c);
		while(c != 32) {
			number = number * 10 + c - 48;
			map.get(c);
		}
		nodes[count].ID = number;
		number = 0;

		//Read locationx
		map.get(c);
		while(c != 32)
		{
			number = number * 10 + c - 48;
			map.get(c);
		}
		nodes[count].locationx = number;
		number = 0;

		//Read locationx
		map.get(c);
		while(c != 32)
		{
			number = number * 10 + c - 48;
			map.get(c);
		}
		nodes[count].locationy = number;
		number = 0;

		//Read and store first neighbor
		map.get(c);
		while(c != 32) {
			number = number * 10 + c - 48;
			map.get(c);
		}
		if(number < nodes_number)
		{
			start = new neighbor[1];
			start->nodeID = number;
			start->next = NULL;
			index = start;
			nodes[count].neighbor_number++;
		}
		number = 0;

		//Read rest neighbors
		while(cl == 0) {
			map.get(c);
			if(c == 32) {
				if(number < nodes_number)
				{
					index->next = new neighbor;
					index = index->next;
					index->nodeID = number;
					index->next = NULL;
					nodes[count].neighbor_number++;
				}
				number = 0;
			}
			else if(c == 10) {
				nodes[count].recipientList = start;
				cl = 1;
				count++;
			}
			else
				number = number * 10 + c - 48;
		}
	}
}

void graph::Showmap(int number) {
	neighbor *index = NULL;

	if(number > MAX_NODE_NUMBER){
		cout << "Error. choose a number smaller than " << MAX_NODE_NUMBER << endl;
		return;
	}
	//Show result
	cout << "ID: " << nodes[number-1].ID << endl;
	cout << "Friends:" << endl;
	index = nodes[number-1].recipientList;
	while(index != NULL) 
	{
		cout << index->nodeID << " ";
		index = index->next;
	}
	cout << endl;
	cout << "x: " << nodes[number-1].locationx << endl;
	cout << "y: " << nodes[number-1].locationy << endl;
	index = nodes[number-1].nearby;
	cout << "Nodes nearby:" << endl;
	while(index != NULL)
	{
		cout << index->nodeID << " ";
		index = index->next;
	}
	cout << endl;
	cout << "Number of channels: " << nodes[number-1].neighbor_number << endl;
	cout << "Status: " << nodes[number-1].on << endl;
	cout << endl;
}

void graph::humancontact()
{
	int i = 0;
	int j = 0;
	neighbor *index = NULL;

	for(i=0;i<nodes_number;i++)
	{
		for(j=0;j<nodes_number;j++)
		{
			if((abs(nodes[i].locationx - nodes[j].locationx) <= HUMAN_CONTACT_DISTANCE) &&
				(abs(nodes[i].locationy - nodes[j].locationy) <= HUMAN_CONTACT_DISTANCE) && (i != j))
			{
				if(nodes[i].nearby == NULL)
				{
					nodes[i].nearby = new neighbor;
					nodes[i].nearby->nodeID = nodes[j].ID;
					nodes[i].nearby->next = NULL;
					index = nodes[i].nearby;
				}
				else
				{
					index->next = new neighbor;
					index = index->next;
					index->nodeID = nodes[j].ID;
					index->next = NULL;
				}
			}
		}
	}
}



void graph::drawGraph(){
	neighbor *index;
	float xExpansionRatio = 2.5, yExpansionRatio = 1.5;
	
	HDC hdc = GetDC(0);
	HDC memDC = CreateCompatibleDC(hdc);
	
	HBITMAP hMemBmp = CreateCompatibleBitmap(hdc,10,10);
    HBITMAP hOldBmp =  (HBITMAP)SelectObject(memDC,hMemBmp);


	
    HPEN hWhiteLineThickPen, hBlackLineThickPen, hWhiteLineThinPen, hBlackLineThinPen, hGrayLineThinPen, hPenOld;
	COLORREF qWhiteLine, qGrayLine, qBlackLine;
	qWhiteLine = RGB(255, 255, 255);
	hWhiteLineThickPen = CreatePen(PS_SOLID, 5, qWhiteLine);
	hWhiteLineThinPen = CreatePen(PS_SOLID, 1, qWhiteLine);

	qGrayLine = RGB(200, 200, 200);
	hGrayLineThinPen = CreatePen(PS_SOLID, 1, qGrayLine);

	qBlackLine = RGB(0, 0, 0);
	hBlackLineThickPen = CreatePen(PS_SOLID, 5, qBlackLine);
	hBlackLineThinPen = CreatePen(PS_SOLID, 1, qBlackLine);

	hPenOld = (HPEN)SelectObject(hdc, hWhiteLineThickPen);

	// cls part
	//BitBlt(hdc, 0,0, 1023, 768, 0,0,0, WHITENESS);
	// cls part

	//::Rectangle(hdc, 0, 0, 1024, 768);
	for(int i = 0; i < MAX_NODE_NUMBER; i++){

		index = nodes[i].recipientList;
		//while(index != NULL){
		//	hPenOld = (HPEN)SelectObject(hdc, hWhiteLineThinPen);
		//	getNode(index->nodeID);
		//	::MoveToEx(hdc, nodes[i].locationx * xExpansionRatio, nodes[i].locationy, NULL);
		//	::LineTo(hdc, getNode(index->nodeID).locationx * xExpansionRatio, getNode(index->nodeID).locationy * yExpansionRatio);
		//	index = index->next;
		//}

		if(nodes[i].on){
			while(index != NULL){
				if(getNode(index->nodeID).on){
					hPenOld = (HPEN)SelectObject(hdc, hGrayLineThinPen);
					::MoveToEx(hdc, nodes[i].locationx * xExpansionRatio, nodes[i].locationy * yExpansionRatio, NULL);
					::LineTo(hdc, getNode(index->nodeID).locationx * xExpansionRatio, getNode(index->nodeID).locationy * yExpansionRatio);
				}else{
					hPenOld = (HPEN)SelectObject(hdc, hBlackLineThinPen);
					::MoveToEx(hdc, nodes[i].locationx * xExpansionRatio, nodes[i].locationy * yExpansionRatio, NULL);
					::LineTo(hdc, getNode(index->nodeID).locationx * xExpansionRatio, getNode(index->nodeID).locationy * yExpansionRatio);
				}
				index = index->next;
			}
		}else{
			hPenOld = (HPEN)SelectObject(hdc, hBlackLineThinPen);
			::MoveToEx(hdc, nodes[i].locationx * xExpansionRatio, nodes[i].locationy * yExpansionRatio, NULL);
			::LineTo(hdc, getNode(index->nodeID).locationx * xExpansionRatio, getNode(index->nodeID).locationy * yExpansionRatio);
		}
	}
	for(int i = 0; i < MAX_NODE_NUMBER; i++){
		if(nodes[i].on){
			hPenOld = (HPEN)SelectObject(hdc, hWhiteLineThickPen);
			::Ellipse(hdc, nodes[i].locationx * xExpansionRatio, nodes[i].locationy * yExpansionRatio, nodes[i].locationx * xExpansionRatio + 5, nodes[i].locationy * yExpansionRatio + 5);
		}else{
			hPenOld = (HPEN)SelectObject(hdc, hBlackLineThickPen);
			::Ellipse(hdc, nodes[i].locationx * xExpansionRatio, nodes[i].locationy * yExpansionRatio, nodes[i].locationx * xExpansionRatio + 5, nodes[i].locationy * yExpansionRatio + 5);
		}
	}

	//BitBlt(hdc, 0, 0, 10, 10, memDC, 0, 0, WHITENESS);

    // Always select the old bitmap back into the device context
    SelectObject(memDC, hOldBmp);
    DeleteObject(hMemBmp);
    DeleteDC(memDC);
	DeleteDC(hdc);

    /*::Rectangle(hdc, 200, 200, 300, 300);
	::Ellipse(hdc, 500, 500, 600, 600);
	::MoveToEx(hdc, 400, 400, NULL);
	::LineTo(hdc, 500, 500);*/
::ReleaseDC(0, hdc);
}

void graph::cls()
{
	
     POINT pt;
     HDC hdc;
     MoveToEx(hdc,0,0,&pt);
     HANDLE  hConsoleOut; 
     DWORD    dummy;
     COORD    Home = { 0, 0 };
     hConsoleOut = GetStdHandle( STD_OUTPUT_HANDLE );
     FillConsoleOutputCharacter( 
                 hConsoleOut, ' ', pt.x * pt.y,   Home,  &dummy );
     pt.x=0;
     pt.y =0;
     MoveToEx(hdc,pt.x,pt.y ,&pt);

}
